package mc.support.service.common.impl;

import mc.support.util.PlainUtil;
import org.apache.commons.lang.StringUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created with IntelliJ IDEA. <br/>
 * Author: francis Yun    <br/>
 * Date: 2013-12-13  <br/>
 */
public class CacheKeyMgr {

    private Map<Class<?>, String> keyPrefixCache = new ConcurrentHashMap<Class<?>, String>();

    public String getKey(Class<?> clazz, String...subjects) {
        return getKey(clazz, Policy.staticly, subjects);
    }

    public String getKey(Class<?> clazz, Policy p, String...subjects) {
        String keyPrefix = null;
        if ( null != clazz ) {
            keyPrefix = getKeyPrefix( clazz, p );
        }
        return PlainUtil.connectToStr( keyPrefix, '_', StringUtils.join( subjects ,'_' ) );
    }

    private String getKeyPrefix(Class<?> clazz, Policy p) {
        String prefix = keyPrefixCache.get( clazz );
        if ( null == prefix ) {
            synchronized ( clazz ) {
                prefix = keyPrefixCache.get( clazz );
                if ( null == prefix ) {
                    String clazzName = clazz.getName();
                    try {
                        if ( Policy.dynamicly == p ) {
                            long ns = System.nanoTime();
                            prefix = encode( clazzName + ns );
                        } else {
                            prefix = encode( clazzName );
                        }
                        keyPrefixCache.put( clazz, prefix );
                    } catch (NoSuchAlgorithmException e) {
                        //won't happen
                    }
                }
            }
        }

        return prefix;
    }

    public static String encode(String str) throws NoSuchAlgorithmException {
        MessageDigest digester = MessageDigest.getInstance("MD5");
        digester.update(str.getBytes());
        byte[] hash = digester.digest();
        StringBuilder hexString = new StringBuilder();
        for (byte aHash : hash) {
            if ((0xff & aHash) < 0x10) {
                hexString.append("0").append(Integer.toHexString((0xFF & aHash)));
            } else {
                hexString.append(Integer.toHexString(0xFF & aHash));
            }
        }
        return hexString.toString();
    }

    public enum Policy {
        staticly,
        dynamicly
    }

}
